//
//  NSObject+DicModel.m
//  ConvertDicToModel
//
//  Created by 范伟 on 16/3/16.
//  Copyright © 2016年 FanWei. All rights reserved.
//

#import "NSObject+DicModel.h"
#import <objc/runtime.h>

const char * FW_PropertiesKey = "FW_PropertiesKey";

@implementation NSObject (DicModel)

+ (instancetype)fw_objWithDict:(NSDictionary *)dict {
    // 获取协议方法中定义的属性影射表，记录数组中包含的`类型`
    NSDictionary *mapDict;
    id object = self;
    if ([object respondsToSelector:@selector(fw_classMapInfo)]) {
        mapDict = [object fw_classMapInfo];
    }
    
    NSDictionary *propertiesDict = [self fw_getClassProperties];
    //使用“本类”进行实例化
    id model = [[self alloc] init];
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        //判断key是否存在
        if (propertiesDict[key] == nil) {
            return;
        }
        NSString *type = propertiesDict[key];
        // 使用 KVC 设置数值，需要扩展...
        if ([type isEqualToString:@""] || [type isEqualToString:@"NSString"]) {
            [model setValue:obj forKey:key];
        }
        if ([object isKindOfClass:[NSDictionary class]]) {
            NSString *name = propertiesDict[key];
            Class class = NSClassFromString(name);
            //递归，给子类设置属性
            [model setValue:[class fw_objWithDict:obj] forKey:key];
        }
        //数组判断
        if ([type isEqualToString:@"NSArray"]) {
            NSString *className = mapDict[key];
            if (className != nil) {
                NSMutableArray *objs = [NSMutableArray array];
                Class class = NSClassFromString(className);
                for (NSDictionary *valueDict in obj) {
                    [objs addObject:[class fw_objWithDict:valueDict]];
                }
                //// KVC 给当前属性设置数值
                [model setValue:objs forKey:key];
            }
        }
    }];
    return nil;
}

+ (NSDictionary *)fw_getClassProperties {
    
    NSDictionary *propertiesDict = objc_getAssociatedObject(self, FW_PropertiesKey);
    if (propertiesDict != nil) {
        return propertiesDict;
    }
    
    unsigned int count = 0;
    objc_property_t *properties = class_copyPropertyList(self, &count);
    NSMutableDictionary *infoDict = [NSMutableDictionary dictionary];
    for (unsigned int i = 0; i < count; ++ i) {
        objc_property_t ppt = properties[i];
        char const *cName = property_getName(ppt);
        NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];
        char const *cAttr = property_getAttributes(ppt);
        NSString *attr = [NSString stringWithCString:cAttr encoding:NSUTF8StringEncoding];
        
        NSLog(@"%@  %@", name, attr);
        /**
         如果属性是自定义对象，可以通过 attribute 获得
         如果属性是一个数组，通过 attribute 只能知道是 NSArray 类型，并不能知道 NSArray 中存放 什么 类 的对象！
         因此：所有字典转模型的框架，都有类似的处理，通过协议方法，调用对应的方法之后，判断 NSArray 中存放的对象类型！
         */
        //记录对象类型
        NSString *pattern = @"T\"(.*?)\"";
        NSError *error = nil;
        NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:pattern
                                                                               options:0
                                                                                 error:&error];
        if (error != nil) {
            NSLog(@"error");
        }
        NSTextCheckingResult *result = [regEx firstMatchInString:attr options:0 range:NSMakeRange(0, attr.length)];
        if (result != nil) {
            NSString *type = [attr substringWithRange:[result rangeAtIndex:1]];
            [infoDict setObject:type forKey:name];
        } else {
            [infoDict setObject:@"" forKey:name];
        }
    }
    free(properties);
    //设置关联对象
    objc_setAssociatedObject(self, FW_PropertiesKey, infoDict.copy, OBJC_ASSOCIATION_COPY_NONATOMIC);
    return infoDict.copy;
}
@end
